home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / tcpcmd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-27  |  17.1 KB  |  727 lines

  1. /* TCP control and status routines
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Mods by G1EMM
  5.  * Mods by WG7J
  6.  * Mods by WA3DSP
  7.  * Mods by PA0GRI
  8.  * Copyright 1992 Gerard J van der Grinten, PA0GRI
  9.  */
  10.  
  11. #include <stdio.h>
  12. #include <dos.h>
  13. #include "global.h"
  14. #include "config.h"
  15. #include "timer.h"
  16. #include "mbuf.h"
  17. #include "netuser.h"
  18. #include "internet.h"
  19. #include "tcp.h"
  20. #include "cmdparse.h"
  21. #include "commands.h"
  22.  
  23. #ifdef  TCPACCESS
  24. static int doaccess __ARGS((int argc,char *argv[],void *p));
  25. void addtaccess __ARGS((int32 target,unsigned int bits,int16 low,int16 high,int16 permit));
  26. #endif
  27. static int doirtt __ARGS((int argc,char *argv[],void *p));
  28. static int domss __ARGS((int argc,char *argv[],void *p));
  29. static int dortt __ARGS((int argc,char *argv[],void *p));
  30. static int dotcpkick __ARGS((int argc,char *argv[],void *p));
  31. static int dotcpreset __ARGS((int argc,char *argv[],void *p));
  32. static int dotcpretries __ARGS((int argc,char *argv[],void *p));
  33. static int dotcpstat __ARGS((int argc,char *argv[],void *p));
  34. static int dotcptimer __ARGS((int argc,char *argv[],void *p));
  35. static int dotcptr __ARGS((int argc,char *argv[],void *p));
  36. static int dowindow __ARGS((int argc,char *argv[],void *p));
  37. static int dosyndata __ARGS((int argc,char *argv[],void *p));
  38. static int doview __ARGS((int argc,char *argv[],void *p));
  39. static int dotcpblimit __ARGS((int argc,char *argv[],void *p));
  40. void rxtx_data_compute __ARGS((struct tcb *tcb,int32 *sent,int32 *recvd));
  41. static int tstat __ARGS((void));
  42. #ifdef TCPACCESS
  43. struct rtaccess *TCPaccess = NULLACCESS; /* access list */
  44. #endif
  45.  
  46. /* TCP subcommand table */
  47. static struct cmds DFAR Tcpcmds[] = {
  48. #ifdef  TCPACCESS
  49.     "access",    doaccess,    0,    0, NULLCHAR,
  50. #endif
  51.     "blimit",       dotcpblimit,    0, 0,   NULLCHAR,
  52.     "irtt",         doirtt,         0, 0,   NULLCHAR,
  53.     "kick",         dotcpkick,      0, 2,   "tcp kick <tcb>",
  54.     "mss",          domss,          0, 0,   NULLCHAR,
  55.     "reset",        dotcpreset,     0, 2,   "tcp reset <tcb>",
  56.     "retries",      dotcpretries,   0,0,    NULLCHAR,
  57.     "rtt",          dortt,          0, 3,   "tcp rtt <tcb> <val>",
  58.     "status",       dotcpstat,      0, 0,   NULLCHAR,
  59.     "syndata",      dosyndata,      0, 0,   NULLCHAR,
  60.     "timertype",    dotcptimer,     0, 0,   NULLCHAR,
  61.     "trace",        dotcptr,        0, 0,   NULLCHAR,
  62.     "view",         doview,         0, 0,   NULLCHAR,
  63.     "window",       dowindow,       0, 0,   NULLCHAR,
  64.     NULLCHAR,
  65. };
  66. int
  67. dotcp(argc,argv,p)
  68. int argc;
  69. char *argv[];
  70. void *p;
  71. {
  72.     return subcmd(Tcpcmds,argc,argv,p);
  73. }
  74. static int
  75. dotcptr(argc,argv,p)
  76. int argc;
  77. char *argv[];
  78. void *p;
  79. {
  80.     return setbool(&Tcp_trace,"TCP state tracing",argc,argv);
  81. }
  82.  
  83. /* Eliminate a TCP connection */
  84. static int
  85. dotcpreset(argc,argv,p)
  86. int argc;
  87. char *argv[];
  88. void *p;
  89. {
  90.     register struct tcb *tcb;
  91.     
  92. #ifndef TNOS_68K
  93.     tcb = MK_FP(htoi(argv[1]),8);
  94. #else
  95.     tcb = htoi(argv[1]);
  96. #endif
  97.     if(!tcpval(tcb)){
  98.         tprintf(Notval);
  99.         return 1;
  100.     }
  101.     reset_tcp(tcb);
  102.     return 0;
  103. }
  104.  
  105. /* Set initial round trip time for new connections */
  106. static int
  107. doirtt(argc,argv,p)
  108. int argc;
  109. char *argv[];
  110. void *p;
  111. {
  112.     struct tcp_rtt *tp;
  113.  
  114.     setlong(&Tcp_irtt,"TCP default irtt",argc,argv);
  115.     if(argc < 2){
  116.         for(tp = &Tcp_rtt[0];tp < &Tcp_rtt[RTTCACHE];tp++){
  117.             if(tp->addr != 0){
  118.                 if(tprintf("%s: srtt %lu mdev %lu\n",
  119.                  inet_ntoa(tp->addr),
  120.                  tp->srtt,tp->mdev) == EOF)
  121.                     break;
  122.             }
  123.         }
  124.     }
  125.     return 0;
  126. }
  127.  
  128. /* Set smoothed round trip time for specified TCB */
  129. static int
  130. dortt(argc,argv,p)
  131. int argc;
  132. char *argv[];
  133. void *p;
  134. {
  135.     register struct tcb *tcb;
  136. #ifndef TNOS_68K
  137.     tcb = MK_FP(htoi(argv[1]),8);
  138. #else
  139.     tcb = htoi(argv[1]);
  140. #endif
  141.     if(!tcpval(tcb)){
  142.         tprintf(Notval);
  143.         return 1;
  144.     }
  145.     tcb->srtt = atol(argv[2]);
  146.     return 0;
  147. }
  148.  
  149. /* Force a retransmission */
  150. static int
  151. dotcpkick(argc,argv,p)
  152. int argc;
  153. char *argv[];
  154. void *p;
  155. {
  156.     register struct tcb *tcb;
  157. #ifndef TNOS_68K
  158.     tcb = MK_FP(htoi(argv[1]),8);
  159. #else
  160.     tcb = htoi(argv[1]);
  161. #endif
  162.     if(kick_tcp(tcb) == -1){
  163.         tprintf(Notval);
  164.         return 1;
  165.     }
  166.     return 0;
  167. }
  168.  
  169. /* Set default maximum segment size */
  170. static int
  171. domss(argc,argv,p)
  172. int argc;
  173. char *argv[];
  174. void *p;
  175. {
  176.     return setshort(&Tcp_mss,"TCP MSS",argc,argv);
  177. }
  178.  
  179. /* Set default window size */
  180. static int
  181. dowindow(argc,argv,p)
  182. int argc;
  183. char *argv[];
  184. void *p;
  185. {
  186.     return setshort(&Tcp_window,"TCP window",argc,argv);    
  187. }
  188.  
  189. static int
  190. dosyndata(argc,argv,p)
  191. int argc;
  192. char *argv[];
  193. void *p;
  194. {
  195.     return setbool(&Tcp_syndata,"TCP syn+data piggybacking",argc,argv);
  196. }
  197.  
  198. extern int Tcp_retries;
  199.  
  200. /* Set maximum number of backoffs before resetting the connection */
  201. static int
  202. dotcpretries(argc,argv,p)
  203. int argc;
  204. char *argv[];
  205. void *p;
  206. {
  207.     return setint(&Tcp_retries,"max. retries",argc,argv);
  208. }
  209.  
  210. extern int Tcp_blimit;
  211.  
  212. /* Set backoff limit on the connection; from N1BEE */
  213. static int
  214. dotcpblimit(argc,argv,p)
  215. int argc;
  216. char *argv[];
  217. void *p;
  218. {
  219.     return setint(&Tcp_blimit,"backoff limit",argc,argv);
  220. }
  221.  
  222. /* Display status of TCBs */
  223. static int
  224. dotcpstat(argc,argv,p)
  225. int argc;
  226. char *argv[];
  227. void *p;
  228. {
  229.     register struct tcb *tcb;
  230.  
  231.     if(argc < 2){
  232.         tstat();
  233.     } else {
  234.  
  235. #ifndef TNOS_68K
  236.     tcb = MK_FP(htoi(argv[1]),8);
  237. #else
  238.     tcb = htoi(argv[1]);
  239. #endif
  240.     if(!tcpval(tcb))
  241.         tprintf(Notval);
  242.     else
  243.         st_tcp(tcb);
  244.     }
  245.     return 0;
  246. }
  247.  
  248. /* Dump TCP stats and summary of all TCBs
  249. /*     &TCB Rcv-Q Snd-Q  Local socket           Remote socket          State
  250.  *     1234     0     0  xxx.xxx.xxx.xxx:xxxxx  xxx.xxx.xxx.xxx:xxxxx  Established
  251.  * Dump display for TNOS_68K
  252.  *     &TCB     Rcv-Q Snd-Q  Local socket           Remote socket          State
  253.  *     123456       0     0  xxx.xxx.xxx.xxx:xxxxx  xxx.xxx.xxx.xxx:xxxxx  Established
  254.  */
  255. static int
  256. tstat()
  257. {
  258.     register int i;
  259.     register struct tcb *tcb;
  260.     int j;
  261.  
  262.     for(j=i=1;i<=NUMTCPMIB;i++){
  263.         if(Tcp_mib[i].name == NULLCHAR)
  264.             continue;
  265.         tprintf("(%2u)%-20s%10lu",i,Tcp_mib[i].name,
  266.          Tcp_mib[i].value.integer);
  267.         if(j++ % 2)
  268.             tprintf("     ");
  269.         else
  270.             tprintf("\n");
  271.     }
  272.     if((j % 2) == 0)
  273.         tprintf("\n");
  274.  
  275. #ifndef TNOS_68K
  276.     tprintf("&TCB Rcv-Q Snd-Q  Local socket           Remote socket          State\n");
  277. #else
  278.     tprintf("&TCB     Rcv-Q Snd-Q  Local socket           Remote socket          State\n");
  279. #endif
  280.     for(tcb=Tcbs;tcb != NULLTCB;tcb = tcb->next){
  281. #ifndef TNOS_68K
  282.         tprintf("%4.4x%6u%6u  ",
  283. #else
  284.         tprintf("%-8.8x%6u%6u  ",
  285. #endif
  286.         FP_SEG(tcb),tcb->rcvcnt,tcb->sndcnt);
  287.         tprintf("%-23s",pinet(&tcb->conn.local));
  288.         tprintf("%-23s",pinet(&tcb->conn.remote));
  289.         tprintf("%-s",Tcpstates[tcb->state]);
  290.         if(tcb->state == TCP_LISTEN && tcb->flags.clone)
  291.             tprintf(" (S)");
  292.         if(tprintf("\n") == EOF)
  293.             return 0;
  294.     }
  295.     return 0;
  296. }
  297. /* Dump a TCP control block in detail */
  298. void
  299. st_tcp(tcb)
  300. struct tcb *tcb;
  301. {
  302.     int32 sent,recvd;
  303.  
  304.     if(tcb == NULLTCB)
  305.         return;
  306.  
  307.     rxtx_data_compute(tcb,&sent,&recvd);
  308.  
  309.     tprintf("Local: %s",pinet(&tcb->conn.local));
  310.     tprintf(" Remote: %s",pinet(&tcb->conn.remote));
  311.     tprintf(" State: %s\n",Tcpstates[tcb->state]);
  312.     tprintf("      Init seq    Unack     Next Resent CWind Thrsh  Wind  MSS Queue      Total\n");
  313.     tprintf("Send:");
  314.     tprintf("%9lx",tcb->iss);
  315.     tprintf("%9lx",tcb->snd.una);
  316.     tprintf("%9lx",tcb->snd.nxt);
  317.     tprintf("%7lu",tcb->resent);
  318.     tprintf("%6u",tcb->cwind);
  319.     tprintf("%6u",tcb->ssthresh);
  320.     tprintf("%6u",tcb->snd.wnd);
  321.     tprintf("%5u",tcb->mss);
  322.     tprintf("%6u",tcb->sndcnt);
  323.     tprintf("%11lu\n",sent);
  324.  
  325.     tprintf("Recv:");
  326.     tprintf("%9lx",tcb->irs);
  327.     tprintf("         ");
  328.     tprintf("%9lx",tcb->rcv.nxt);
  329.     tprintf("%7lu",tcb->rerecv);
  330.     tprintf("      ");
  331.     tprintf("      ");
  332.     tprintf("%6u",tcb->rcv.wnd);
  333.     tprintf("     ");
  334.     tprintf("%6u",tcb->rcvcnt);
  335.     tprintf("%11lu\n",recvd);
  336.  
  337.     if(tcb->reseq != (struct reseq *)NULL){
  338.         register struct reseq *rp;
  339.  
  340.         tprintf("Reassembly queue:\n");
  341.         for(rp = tcb->reseq;rp != (struct reseq *)NULL; rp = rp->next){
  342.             if(tprintf("  seq x%lx %u bytes\n",
  343.              rp->seg.seq,rp->length) == EOF)
  344.                 return;
  345.         }
  346.     }
  347.     if(tcb->backoff > 0)
  348.         tprintf("Backoff %u ",tcb->backoff);
  349.     if(tcb->flags.retran)
  350.         tprintf("Retrying ");
  351.     switch(tcb->timer.state){
  352.     case TIMER_STOP:
  353.         tprintf("Timer stopped ");
  354.         break;
  355.     case TIMER_RUN:
  356.         tprintf("Timer running (%ld/%ld ms) ",
  357.          (long)read_timer(&tcb->timer),
  358.          (long)dur_timer(&tcb->timer));
  359.         break;
  360.     case TIMER_EXPIRE:
  361.         tprintf("Timer expired ");
  362.     }
  363.     tprintf("SRTT %ld ms Mean dev %ld ms\n",tcb->srtt,tcb->mdev);
  364. }
  365.  
  366. void
  367. rxtx_data_compute(tcb,sent,recvd)
  368. struct tcb *tcb;
  369. int32 *sent;
  370. int32 *recvd;
  371. {
  372.  
  373.     /* Compute total data sent and received; take out SYN and FIN */
  374.     *sent = tcb->snd.una - tcb->iss;        /* Acknowledged data only */
  375.     *recvd = tcb->rcv.nxt - tcb->irs;
  376.     switch(tcb->state){
  377.     case TCP_LISTEN:
  378.     case TCP_SYN_SENT:      /* Nothing received or acked yet */
  379.         *sent = *recvd = 0;     
  380.         break;
  381.     case TCP_SYN_RECEIVED:
  382.         (*recvd)--;     /* Got SYN, no data acked yet */
  383.         *sent = 0;
  384.         break;
  385.     case TCP_ESTABLISHED:   /* Got and sent SYN */
  386.     case TCP_FINWAIT1:      /* FIN not acked yet */
  387.         (*sent)--;
  388.         (*recvd)--;
  389.         break;
  390.     case TCP_FINWAIT2:      /* Our SYN and FIN both acked */
  391.         *sent -= 2;
  392.         (*recvd)--;
  393.         break;
  394.     case TCP_CLOSE_WAIT:    /* Got SYN and FIN, our FIN not yet acked */
  395.     case TCP_CLOSING:
  396.     case TCP_LAST_ACK:
  397.         (*sent)--;
  398.         *recvd -= 2;
  399.         break;
  400.     case TCP_TIME_WAIT:     /* Sent and received SYN/FIN, all acked */
  401.         *sent -= 2;
  402.         *recvd -= 2;
  403.         break;
  404.     }
  405. }
  406.  
  407. /* TCP View Command - D. Crompton 1/92 */
  408. /* Modified for sorted display and     */
  409. /* two views - tcp view b|t - 3/92     */
  410.  
  411. static int
  412. doview(argc,argv,p)
  413. int argc;
  414. char *argv[];
  415. void *p;
  416.  
  417. {
  418.     register struct tcb *tcb;
  419.     int32 sent,recvd;
  420.     int i,j,k=0,vtype;
  421.     char temp[40];
  422.     char *buf;
  423.  
  424.     if(argc == 1)
  425.         vtype = 1;
  426.     else {
  427.         switch (argv[1][0]) {
  428.             case 'b':  vtype=1;
  429.                break;
  430.             case 't':  vtype=0;
  431.                break;
  432.             default:   tprintf("Use: tcp view <bytes|timers>\n");
  433.                return 0;
  434.         }
  435.     }
  436.     
  437.     for(tcb=Tcbs,i=0;tcb != NULLTCB;tcb = tcb->next){
  438.         if(tcb->state == TCP_LISTEN)
  439.             continue;
  440.         i++;
  441.     }
  442.     
  443.     if (i) {
  444.      buf=mallocw(i*80);
  445.  
  446.      if (vtype) {
  447.       tprintf("                                               Send  Send       Receive Receive\n");
  448.       tprintf("Remote Socket:Port:Local Port/State   &TCB     Bytes Retries      Bytes Retries\n");
  449.      } else {
  450.       tprintf("Remote Socket:Port:Local Port/State   &TCB Boff State      Timer          SRTT\n");
  451.      }                                                                     
  452.      for(tcb=Tcbs,j=0;tcb != NULLTCB;tcb = tcb->next){
  453.         if(tcb->state == TCP_LISTEN)
  454.             continue;
  455.          
  456.         strcpy(temp,pinet(&tcb->conn.remote));
  457.         strcat(temp,strstr(pinet(&tcb->conn.local),":"));
  458.         strcat(temp,"/");
  459.         strcat(temp,Tcpstates[tcb->state]);
  460.         temp[37]=0;
  461.         k=sprintf(&buf[j],"%-37s",temp);
  462.         sprintf(temp,"%8lx",ptol(tcb));
  463.         temp[4]=0;
  464.         k+=sprintf(&buf[j+k]," %4s",temp);
  465.         if (vtype) {
  466.           rxtx_data_compute(tcb,&sent,&recvd);
  467.           k+=sprintf(&buf[j+k],"%10lu ",sent);
  468.           k+=sprintf(&buf[j+k],"%7lu ",tcb->resent);
  469.           k+=sprintf(&buf[j+k],"%10lu ",recvd);
  470.           sprintf(&buf[j+k],"%7lu",tcb->rerecv);
  471.         } else {
  472.           k+=sprintf(&buf[j+k]," %4u",tcb->backoff);
  473.           if(tcb->flags.retran)
  474.               k+=sprintf(&buf[j+k]," Retry ");
  475.           else
  476.               k+=sprintf(&buf[j+k],"  Try  ");
  477.           switch(tcb->timer.state) {
  478.                case TIMER_STOP:
  479.                 k+=sprintf(&buf[j+k],"      Stopped");
  480.                 break;
  481.                case TIMER_RUN:
  482.                 k+=sprintf(&buf[j+k]," Run (");
  483.                 if ((long)dur_timer(&tcb->timer)<10000) {
  484.                   k+=sprintf(&buf[j+k],"%ld/%ld)ms",
  485.                    (long)read_timer(&tcb->timer),
  486.                    (long)dur_timer(&tcb->timer));
  487.                 } else {
  488.                 if (((long)read_timer(&tcb->timer)/1000)>9999) {
  489.                   k+=sprintf(&buf[j+k],">9999/9999)s");
  490.                 } else {
  491.                   k+=sprintf(&buf[j+k],"%ld/%ld)s",
  492.                    (long)read_timer(&tcb->timer)/1000,
  493.                    (long)dur_timer(&tcb->timer)/1000);
  494.                  }
  495.                 }
  496.                 break;
  497.                case TIMER_EXPIRE:
  498.                 k+=sprintf(&buf[j+k],"      Expired");
  499.           }
  500.           for (;k<73;k++)
  501.                buf[j+k]=' ';
  502.           if ((tcb->srtt)<10000) {
  503.               sprintf(&buf[j+73],"%4ldms",tcb->srtt);
  504.           } else {
  505.           if ((tcb->srtt/1000)>9999) {
  506.               sprintf(&buf[j+73],">9999s");
  507.           } else {
  508.               sprintf(&buf[j+73],"%4lds",tcb->srtt/1000);
  509.            }
  510.           }
  511.          }
  512.          j+=80;
  513.         }
  514.  
  515.         qsort(buf,(size_t)i,80,strcmp);
  516.  
  517.         for (j=0,k=0;j<i;j++,k+=80) {
  518.         tprintf("%s",&buf[k]);
  519.         if(tprintf("\n") == EOF)
  520.             return 0;
  521.         }
  522.         free(buf);
  523.       }
  524.     return 0;
  525. }
  526.  
  527. /* tcp timers type - linear v exponential */
  528. static
  529. dotcptimer(argc,argv,p)
  530. int argc ;
  531. char *argv[] ;
  532. void *p ;
  533. {
  534.     extern int tcptimertype;
  535.  
  536.     if (argc < 2) {
  537.         tprintf("Tcp timer type is %s\n", tcptimertype ? "linear" : "exponential" ) ;
  538.         return 0 ;
  539.     }
  540.     
  541.     switch (argv[1][0]) {
  542.         case 'l':
  543.         case 'L':
  544.             tcptimertype = 1 ;
  545.             break ;
  546.         case 'e':
  547.         case 'E':
  548.             tcptimertype = 0 ;
  549.             break ;
  550.         default:
  551.             tprintf("use: tcp timertype [linear|exponential]\n") ;
  552.             return -1 ;
  553.     }
  554.  
  555.     return 0 ;
  556. }
  557. #ifdef  TCPACCESS
  558. static int
  559. doaccess(argc,argv,p)
  560. int argc;
  561. char *argv[];
  562. void *p;
  563. {
  564.     struct iface *ifp;
  565.     int32 target;
  566.     unsigned bits;
  567.     char *bitp;
  568.     int16 lport,hport,state;
  569.     char *cp; /* for printing the table */
  570.     struct rtaccess *tpacc;
  571.     struct rtaccess *head;
  572.     struct rtaccess *prev;
  573.  
  574.     if(argc == 1){ /* print out the table */
  575.         tprintf("IP Address      Mask  Low Port High Port State\n");
  576.         for(tpacc = TCPaccess;tpacc != NULLACCESS;tpacc = tpacc->nxtbits){
  577.             if(tpacc->target != 0)
  578.                 cp = inet_ntoa(tpacc->target);
  579.             else
  580.                 cp = "all";
  581.             tprintf("%-16s",cp);
  582.             tprintf("%4u ",tpacc->bits);
  583.             tprintf("%9u",tpacc->lowport);
  584.             tprintf("%10u ",tpacc->highport);
  585.             if(tpacc->status)
  586.                 cp = "deny";
  587.             else
  588.                 cp = "permit";
  589.             tprintf("%-6s\n",cp);
  590.         }
  591.         return 0;
  592.     }
  593.  
  594.     if(strcmp(argv[1],"permit") == 0){
  595.         state = 0;
  596.     } else {
  597.         if((strcmp(argv[1],"deny") == 0)
  598.         || (strcmp(argv[1],"delete") == 0)){
  599.             state = -1;
  600.         } else {
  601.             tprintf(" Format: tcp access <permit|deny|delete> <dest addr>[/<bits>] [lowport [highport]]\n");
  602.             return 1;
  603.         }
  604.     }
  605.     if(strcmp(argv[2],"all") == 0){
  606.         target = 0;
  607.         bits = 0;
  608.     } else {
  609.         /* If IP address is followed by an optional slash and
  610.          * a length field, (e.g., 128.96/16) get it;
  611.          * otherwise assume a full 32-bit address
  612.          */
  613.         if((bitp = strchr(argv[2],'/')) != NULLCHAR){
  614.             /* Terminate address token for resolve() call */
  615.             *bitp++ = '\0';
  616.             bits = atoi(bitp);
  617.         } else
  618.             bits = 32;
  619.  
  620.         if((target = resolve(argv[2])) == 0){
  621.             tprintf(Badhost,argv[2]);
  622.             return 1;
  623.         }
  624.     }
  625.  
  626.     if(argc > 3){
  627.         if(strcmp(argv[3],"all") == 0){
  628.             lport = 1;
  629.             hport = 65534;
  630.         } else {
  631.             lport = atoi(argv[3]);
  632.             hport = lport;
  633.         }
  634.     } else {
  635.         lport = 0;
  636.         hport = 0;
  637.     }
  638.     if(argc > 4)
  639.         hport = atoi(argv[4]);
  640.  
  641.     if(strcmp(argv[1],"delete") == 0){
  642.         prev = NULLACCESS;
  643.         head = tpacc = TCPaccess;
  644.         while(tpacc != NULLACCESS){
  645.             head = tpacc;
  646.             tpacc = tpacc->nxtbits;
  647.             if((head->target == target) &&
  648.                (head->bits == bits)     &&
  649.                (head->lowport == lport) &&
  650.                (head->highport == hport)) { /*match*/
  651.  
  652.  
  653.                 /*now delete. watch for special cases*/
  654.                 if(head == TCPaccess) /* first in chain */
  655.                     TCPaccess = head->nxtbits;
  656.                 else
  657.                     /*
  658.                       sanity check: we cant get here with
  659.                       prev == NULLACCESS !!
  660.                      */
  661.                     prev->nxtbits = tpacc;
  662.                 free(head);
  663.                 return 0;
  664.             }
  665.             prev = head;
  666.         }
  667.         tprintf("Not found.\n");
  668.         return 1;
  669.     }
  670.     /* add the access */
  671.     addtaccess(target,bits,lport,hport,state);
  672.     return 0;
  673. }
  674. /* add an entry to the access control list */
  675. /* not a lot of error checking 8-) */
  676. void
  677. addtaccess(target,bits,low,high,permit)
  678. int32 target;           /* Target IP address prefix */
  679. unsigned int bits;      /* Size of target address prefix in bits (0-32) */
  680. int16 low;
  681. int16 high;
  682. int16 permit;
  683. {
  684.     struct rtaccess *tpacc; /*temporary*/
  685.     struct rtaccess *holder; /*for the new record*/
  686.  
  687.     holder = (struct rtaccess *)callocw(1,sizeof(struct rtaccess));
  688.     holder->nxtiface = NULLACCESS;
  689.     holder->nxtbits = NULLACCESS;
  690.     holder->target = target;
  691.     holder->bits = bits;
  692.     holder->lowport = low;
  693.     holder->highport = high;
  694.     holder->status = permit;
  695.     if((tpacc = TCPaccess) == NULLACCESS){
  696.         TCPaccess = holder;
  697.     } else {
  698.         while(tpacc->nxtbits != NULLACCESS)
  699.             tpacc = tpacc->nxtbits;
  700.         tpacc->nxtbits = holder;
  701.     }
  702. }
  703. /* check to see if port is "authorized".  Returns 0 if matching permit record
  704.    is found or no access records exists, -1 if not found or deny record found */
  705. int
  706. tcp_check(accptr,src,port)
  707. struct rtaccess *accptr;
  708. int32 src;
  709. int16 port;
  710. {
  711.     unsigned long mask;
  712.  
  713.     if(accptr == NULLACCESS)
  714.         return 0;        /* no access control */
  715.     for(;accptr != NULLACCESS;accptr = accptr->nxtbits) {
  716.         mask = ~0L << (32 - accptr->bits);
  717.         if(( accptr->target == (mask & src)) &&
  718.           ((( port >= accptr->lowport ) && (port <= accptr->highport))
  719.            || (!accptr->lowport))){
  720.             return (accptr->status);
  721.         }
  722.     }
  723.     return -1; /* fall through to here if not found */
  724. }
  725. #endif
  726.  
  727.